package edu.luc.concordia;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.util.ArrayList;

import javax.swing.JTextField;

import edu.luc.concordia.PurchaseRecorder;
import edu.luc.concordia.ReceiptGenerator;

/**
 * Copyright 2008 Project Concordia
 * <p>
 * This file is part of RetailReturnSystem.
 * <p>
 * RetailReturnSystem is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * <p>
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * <p>
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <a
 * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
 * <hr>
 * The Translation class passes data between the user interface and application.
 * <p>
 * 
 * @author Concordia
 * @version 0.1 2008-10-06
 */

public class Translation implements ActionListener {

	private SystemInitializer mySysInit;
	private PurchaseRecorder myPurchase;
	private ReceiptGenerator myReceipt;
	private Inventory myInventory;
	private PropertyChangeSupport myListeners = new PropertyChangeSupport(this);
	private Returns myReturn;
	private ReportGenerator myReport;
	private boolean isMember;

	/**
	 * Class constructor
	 */
	public Translation() {
		mySysInit = new SystemInitializer();
		myInventory = new Inventory();
		isMember = false;
	}

	/**
	 * Adds a listener to the Translation class.
	 * 
	 * @param ls
	 *            A PropertyChangeListener that listens for events from the
	 *            Translation class.
	 */
	public void addPropertyChangeListener(PropertyChangeListener ls) {
		myListeners.addPropertyChangeListener(ls);
	}

	@Override
	/*
	 * Invoked when an action occurs.
	 * 
	 * @param evt The action invoked.
	 */
	public void actionPerformed(ActionEvent evt) {
		// Called when the user enters the system initialization file
		if (evt.getActionCommand().equals(ActionConstants.SYSTEM_INITIALIZE)) {
			sysInitialize(evt);
		}
		// Called when the user accepts the initialized inventory
		else if (evt.getActionCommand().equals(
				ActionConstants.ACCEPT_INITIALIZE)) {
			// Initialize the PurchaseRecorder with the Inventory
			myPurchase = new PurchaseRecorder(myInventory);
		}
		// Called when the user scans an item
		else if (evt.getActionCommand().equals(ActionConstants.SCAN_ITEM)) {
			// scanItem(evt);
			scanItemC2(evt);
		}
		// Called when the user wants the final receipt
		else if (evt.getActionCommand().equals(ActionConstants.PRINT_RECEIPT)) {
			printReceipt(evt);
		}

		// if GENERATE_REPORT
		// call printReport(evt)
		// if RETURN_RECEIPT
		// call returnReceipt(evt)
		// if RETURN_ITEM
		// call returnItem(evt)
		// if ADD_SCHEME
		// call addPriceScheme(evt)
		// if UPDATE_SCHEME
		// call updatePriceScheme(evt)

		else if (evt.getActionCommand().equals(ActionConstants.REPORT)) {
			printReceipt(evt);
		} else if (evt.getActionCommand()
				.equals(ActionConstants.RETURN_RECEIPT)) {
			printReceipt(evt);
		} else if (evt.getActionCommand().equals(ActionConstants.RETURN_ITEM)) {
			printReceipt(evt);
		} else if (evt.getActionCommand().equals(ActionConstants.ADD_SCHEME)) {
			printReceipt(evt);
		} else if (evt.getActionCommand().equals(ActionConstants.UPDATE_SCHEME)) {
			printReceipt(evt);
		}

	}

	/**
	 * Fires the PropertyChangeEvent immediately.
	 * 
	 * @param evt
	 *            PropertyChangeEvent sent to listeners of the Translation
	 *            class.
	 */
	private void fireUpdate(PropertyChangeEvent evt) {
		myListeners.firePropertyChange(evt);
	}

	/**
	 * Schedules the PropertyChangeEvent for firing.
	 * 
	 * @param evt
	 *            PropertyChangeEvent scheduled for firing.
	 */
	private void scheduleUpdate(final PropertyChangeEvent evt) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				fireUpdate(evt);
			}
		});
	}

	/**
	 * Helper method for ActionPerformed. It is called when the user enters the
	 * system initialization file.
	 * 
	 * @param evt
	 *            ActionEvent passed from the user interface.
	 */
	private void sysInitialize(ActionEvent evt) {
		// The source should be the text field
		JTextField text = (JTextField) evt.getSource();
		File in = new File(text.getText());

		// Initialize the Inventory
		mySysInit.initializeInventory(in, myInventory);

		// Create the events to inform the user interface
		PropertyChangeEvent summary = new PropertyChangeEvent(this,
				PropertyConstants.SYSTEM_INIT_SUMMARY, null, mySysInit
						.listSummary());
		scheduleUpdate(summary);
		PropertyChangeEvent errors = new PropertyChangeEvent(this,
				PropertyConstants.SYSTEN_INIT_ERRORS, null, mySysInit
						.listErrors());
		scheduleUpdate(errors);
	}

	@Deprecated
	private void scanItem(ActionEvent evt) {
		// The source should be the text field
		JTextField text = (JTextField) evt.getSource();
		int quantity = evt.getID();
		String uid = text.getText();

		// Get the scanned item
		Product prod = myPurchase.scanItem(uid, quantity);

		// Create the events to inform the user interface
		if (prod != null) {
			// Get the price and description of the found product
			ArrayList<PriceScheme> scheme = prod.getPriceScheme();
			Double price = new Double(scheme.get(0).getPrice());
			String desc = prod.getDescription();

			PropertyChangeEvent newProduct = new PropertyChangeEvent(this,
					PropertyConstants.PRODUCT_FOUND, price, desc);
			scheduleUpdate(newProduct);
		} else {
			PropertyChangeEvent newProduct = new PropertyChangeEvent(this,
					PropertyConstants.PRODUCT_NOT_FOUND, null, null);
			scheduleUpdate(newProduct);
		}
	}

	/**
	 * Helper method for ActionPerformed. It is called when the user scans an
	 * item.
	 * 
	 * @param evt
	 *            ActionEvent passed from the user interface.
	 */
	private void scanItemC2(ActionEvent evt) {
		// The source should be the text field
		JTextField text = (JTextField) evt.getSource();
		int quantity = evt.getID();
		String uid = text.getText();

		if (uid.length() == 11) {
			if (myInventory.getMemberInfo(uid) != null) {
				isMember = true;
				return;
			}
		}

		// Get the scanned item(s)
		ArrayList<Product> productList = myPurchase.scanItemC2(uid, quantity);

		if (productList == null) {
			PropertyChangeEvent newProduct = new PropertyChangeEvent(this,
					PropertyConstants.PRODUCT_NOT_FOUND, null, null);
			scheduleUpdate(newProduct);
		} else if (productList.size() == 0) {
			PropertyChangeEvent newProduct = new PropertyChangeEvent(this,
					PropertyConstants.LIMIT_REACHED, null, null);
			scheduleUpdate(newProduct);
		} else {
			PropertyChangeEvent newProduct = new PropertyChangeEvent(this,
					PropertyConstants.PRODUCT_FOUND_C2, productList,
					productList.get(0).getDescription());
			scheduleUpdate(newProduct);
		}

	}

	/**
	 * Helper method for ActionPerformed. It is called when the user wants the
	 * final receipt.
	 * 
	 * @param evt
	 *            ActionEvent passed from the user interface.
	 */
	private void printReceipt(ActionEvent evt) {
		// Initialize ReceiptGenerator
		myReceipt = new ReceiptGenerator(myPurchase.getScannedItemsC2());
		// Generate receipt
		ArrayList<String> finalReceipt = myReceipt.generateFinalReceipt();

		// Create the events to inform the user interface
		PropertyChangeEvent receiptEvent = new PropertyChangeEvent(this,
				PropertyConstants.FINAL_RECEIPT, null, finalReceipt);
		scheduleUpdate(receiptEvent);
	}

	private void printReport(ActionEvent evt) {
		// get date range from ActionEvent

		// pass date range to myReport
		// get arraylist<string> from myReport

		// create PropertyChangeEvent
		// source is this
		// propertyName is REPORT_GENERATED
		// oldValue is null
		// newValue is arraylist<string> of report
		// schedule update
	}

	private void returnReceipt(ActionEvent evt) {
		ArrayList<Product> list = (ArrayList<Product>) evt.getSource();

		myReturn = new Returns(list);

		PropertyChangeEvent returnEvent = new PropertyChangeEvent(this,
				PropertyConstants.RETURN_RECEIPT, myReturn
						.generateReturnReceipt(), null);
		scheduleUpdate(returnEvent);

		// get receipt ID from ActionEvent
		// validate receipt ID

		// if receipt ID is valid
		// initialize myReturn
		// create PropertyChangeEvent
		// source is this
		// propertyName is VALID_RECEIPT
		// oldValue is null
		// newValue is date of purchase
		// schedule update
		// if receipt ID is invalid
		// create PropertyChangeEvent
		// source is this
		// propertyName is INVALID_RECEIPT
		// oldValue is null
		// newValue is null
		// schedule update
	}

	private void returnItem(ActionEvent evt) {
		// get product ID and quantity from ActionEvent

		// send product ID and quantity to myReturn
		// get back arraylist of products

		// if arraylist is null (fraudulent return detected)
		// create PropertyChangeEvent
		// source is this
		// propertyName is FRAUD_RETURN
		// oldValue is null
		// newValue is null
		// schedule update
		// if arrayList is not null (valid return)
		// create PropertyChangeEvent
		// source is this
		// propertyName is VALID_RETURN
		// oldValue is arrayList
		// newValue is description of product
		// schedule update
	}

	private void addPriceScheme(ActionEvent evt) {
		// get price scheme from ActionEvent

		// add price scheme to inventory (?)
	}

	private void updatePriceScheme(ActionEvent evt) {
		// get price scheme from action event

		// update price scheme in inventory (?)
	}

}